home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / MacPerl ƒ / Perl Source ƒ / MacPerl / MPEditions.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-22  |  37.1 KB  |  1,359 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPEditions.c    -
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Started    :    17Mar93                                Language    :    MPW C
  10. Modified    :    29May93    MN    Compiles correctly
  11.                 30May93    MN    Support Console Windows
  12.                 18Sep93    MN    Runtime
  13. Last        :    18Sep93
  14. *********************************************************************/
  15.  
  16. #include <OSUtils.h>
  17. #include <Resources.h>
  18. #include <Errors.h>
  19. #include <AppleEvents.h>
  20.  
  21. #include "MPEditions.h"
  22.  
  23. #ifndef RUNTIME
  24.  
  25. /**-----------------------------------------------------------------------
  26.         Name:         GetERefCon
  27.         Purpose:        Return the sectHandle (our own type) stored in
  28.                         the refcon of the SectionRecord.
  29.     -----------------------------------------------------------------------**/
  30.  
  31. #pragma segment  Editions
  32.  
  33. pascal SectHandle GetERefCon(SectionHandle EMSection)
  34. {
  35.     SectHandle aSectHandle;
  36.  
  37.     aSectHandle = (SectHandle)(*EMSection)->refCon;
  38.     return(aSectHandle);
  39. }
  40.  
  41. /**-----------------------------------------------------------------------
  42. Name:         SetERefCon
  43. Purpose:        Store a handle to our own SectRecord in the refcon
  44.                 field of the SectionRecord.
  45. -----------------------------------------------------------------------**/
  46.  
  47. #pragma segment  Editions
  48.  
  49. pascal void SetERefCon(SectionHandle EMSection, SectHandle aSectHandle)
  50. {
  51.     (*EMSection)->refCon = (long)aSectHandle;
  52. }
  53.  
  54. /**-----------------------------------------------------------------------
  55.         Name:         AddSection
  56.         Purpose:        Add our own section record to the document linked
  57.                         list.  Set up the first and last section variables.
  58.     -----------------------------------------------------------------------**/
  59.  
  60. #pragma segment  Editions
  61.  
  62. pascal void AddSection(SectHandle newSection, DPtr aDocument)
  63. {
  64.     if (aDocument->kind != kDocumentWindow)
  65.         return;
  66.         
  67.     /*
  68.         add the section to the document
  69.     */
  70.     aDocument->u.reg.numSections += 1;
  71.  
  72.     /*
  73.         if not NIL, add the new section to the list after the last element
  74.     */
  75.  
  76.     if (aDocument->u.reg.lastSection)
  77.         (*(aDocument->u.reg.lastSection))->fNextSection = newSection;
  78.     else
  79.         aDocument->u.reg.firstSection = newSection;
  80.  
  81.     aDocument->u.reg.lastSection = newSection;
  82.     (*newSection)->fNextSection  = nil;
  83. }
  84.  
  85. /**-----------------------------------------------------------------------
  86.         Name:         CreateSection
  87.         Purpose:        Create a new section record to hold a Publisher or
  88.                         Subscriber. Link this to the SectionRecord.
  89.     -----------------------------------------------------------------------**/
  90.  
  91. #pragma segment  Editions
  92.  
  93. pascal void CreateSection(SectionHandle   EMSection,
  94.                                   short           sectionID,
  95.                                   short           theStart,
  96.                                   short           theEnd,
  97.                                   DPtr            aDocument,
  98.                                   RgnHandle       theBorder)
  99.  
  100. {
  101.     SectHandle    newSection;
  102.  
  103.     if (aDocument->kind != kDocumentWindow)
  104.         return;
  105.         
  106.     /*
  107.         create a section and call AddSection to add it to the list
  108.     */
  109.     newSection = (SectHandle)NewHandle(sizeof(SectRec));
  110.  
  111.     if (newSection) {
  112.         (*newSection)->fSectionID   = sectionID;
  113.         (*newSection)->fNextSection = nil;
  114.         (*newSection)->fSectHandle  = EMSection;
  115.         (*newSection)->fStart       = theStart;
  116.         (*newSection)->fEnd         = theEnd;
  117.         (*newSection)->fCount       = theEnd - theStart;
  118.         (*newSection)->fBorderRgn   = theBorder;
  119.         (*newSection)->fDocument    = aDocument;
  120.  
  121.         /*
  122.             put a reference to our section record in the section's refCon field
  123.         */
  124.  
  125.         SetERefCon(EMSection, newSection);
  126.         AddSection(newSection, aDocument);
  127.     }
  128. }
  129.  
  130.  /**-----------------------------------------------------------------------
  131.         Name:         DeleteASection
  132.         Purpose:        Delete the section from the list.
  133.                         Called when 'Cancel Publisher/Subscriber is chosen in
  134.                         the 'Section Options' dialog.
  135.     -----------------------------------------------------------------------**/
  136.  
  137.     #pragma segment  Editions
  138.  
  139. pascal void DeleteASection(SectHandle sectToDelete, DPtr theDoc)
  140. {
  141.     SectHandle    currSect;
  142.     SectHandle    prevSect;
  143.  
  144.     if (theDoc->kind != kDocumentWindow)
  145.         return;
  146.  
  147.     currSect = theDoc->u.reg.firstSection;
  148.     prevSect = nil;
  149.  
  150.     while (currSect) {
  151.         if (currSect == sectToDelete) {
  152.             /*
  153.                 unlink the section from the list
  154.             */
  155.             if (prevSect)
  156.                 (*prevSect)->fNextSection = (*currSect)->fNextSection;
  157.  
  158.             if (currSect == theDoc->u.reg.firstSection)
  159.                 theDoc->u.reg.firstSection = nil;
  160.  
  161.             if (currSect == theDoc->u.reg.lastSection)
  162.                 theDoc->u.reg.lastSection = nil;
  163.         }
  164.         prevSect = currSect;
  165.         currSect = (*currSect)->fNextSection;
  166.     }
  167. }
  168.  
  169. /**-----------------------------------------------------------------------
  170.         Name:         ReadASection
  171.         Purpose:        Read in a section from disk
  172.                         Read in the rAliasType and rsectionType resources and register
  173.                         the section with the document.
  174.     -----------------------------------------------------------------------**/
  175.  
  176. #pragma segment  Editions
  177.  
  178. pascal void ReadASection(SectHandle aSectHandle)
  179. {
  180.     SectionHandle     aSectionHandle;
  181.     AliasHandle         anAlias;
  182.     OSErr               err;
  183.     FSSpec            myFSSpec;
  184.     Boolean            ignore;
  185.  
  186.     /*read in the rAliasType and rSectionType resources*/
  187.  
  188.     aSectionHandle = (SectionHandle)Get1Resource(rSectionType, (*aSectHandle)->fSectionID);
  189.     err            = HandToHand((Handle *)&aSectionHandle);
  190.     (*aSectHandle)->fSectHandle = aSectionHandle;
  191.     SetERefCon(aSectionHandle, aSectHandle);
  192.  
  193.     anAlias = (AliasHandle)Get1Resource(rAliasType, (*aSectHandle)->fSectionID);
  194.     err     = HandToHand((Handle *)&anAlias);
  195.     (*aSectionHandle)->alias = anAlias;
  196.  
  197.     /*now register the section*/
  198.  
  199.     err = ResolveAlias(nil, (*aSectionHandle)->alias, &myFSSpec, &ignore);
  200.     if (err) {
  201.         ShowError("\pResolve Alias", err);
  202.         return;
  203.     }
  204.  
  205.     err = RegisterSection(&myFSSpec, aSectionHandle, &ignore);
  206.  
  207.     if ((err) && (err != notThePublisherWrn) && (err != multiplePublisherWrn)) {
  208.         ShowError("\pRegisterSection", err);
  209.         return;
  210.     }
  211.     SetSelectionRgn(((*aSectHandle)->fDocument)->theText,
  212.                          (*aSectHandle)->fStart,
  213.                                     (*aSectHandle)->fEnd,
  214.                                     &(*aSectHandle)->fBorderRgn);
  215.     InvalRgn((*aSectHandle)->fBorderRgn);
  216. }
  217.  
  218. /**-----------------------------------------------------------------------
  219. Name:         ReadAllSectionResources
  220. Purpose:        Call the above routine to read in the resources for
  221.                 each section in the document.
  222. -----------------------------------------------------------------------**/
  223. #pragma segment Editions
  224.  
  225. pascal void ReadAllSectionResources(DPtr aDoc)
  226. {
  227.     SectHandle  theSection;
  228.  
  229.     if (aDoc->kind != kDocumentWindow)
  230.         return;
  231.         
  232.     /*read in each section resource*/
  233.  
  234.     theSection = aDoc->u.reg.firstSection;
  235.     while (theSection) {
  236.         ReadASection(theSection);
  237.         theSection = (*theSection)->fNextSection;
  238.     }
  239. }
  240.  
  241. /**-----------------------------------------------------------------------
  242. Name:         ReadSectionRecords
  243. Purpose:        Read in all the 'sect' resources and form list
  244.                 of sections in the document.    This is called from the
  245.                 main read document routine.
  246. -----------------------------------------------------------------------**/
  247. #pragma segment  Editions
  248.  
  249. pascal void ReadSectionRecords(DPtr aDoc)
  250. {
  251.     short         theID;
  252.     SectHandle    aSectHandle;
  253.     OSErr         err;
  254.     short         theCount;
  255.  
  256.     /*read in all the 'sect' resources for our document's sections*/
  257.  
  258.     if (aDoc->kind != kDocumentWindow)
  259.         return;
  260.         
  261.     theCount = aDoc->u.reg.numSections;
  262.     if (theCount == 0)
  263.         return;
  264.  
  265.     aDoc->u.reg.numSections = 0;
  266.     for (theID = 1; theID <= theCount; theID++) {
  267.         aSectHandle = (SectHandle)Get1Resource('SECT', theID);
  268.         err = HandToHand((Handle *)&aSectHandle);
  269.  
  270.         /*now add it to the list*/
  271.  
  272.         if (aSectHandle)
  273.             AddSection(aSectHandle, aDoc);
  274.  
  275.         /*here we should recalculate the region for the bounds*/
  276.  
  277.         (*aSectHandle)->fBorderRgn = NewRgn();
  278.  
  279.         (*aSectHandle)->fDocument  = aDoc;
  280.     }
  281. }
  282.  
  283. /**-----------------------------------------------------------------------
  284.         Name:             SaveASection
  285.         Purpose:        Write out the 'sect', rAliasType and rSectionType resources
  286.                                 to file.    Called when the document is saved.
  287.     -----------------------------------------------------------------------**/
  288.  
  289. #pragma segment Editions
  290.  
  291. pascal void SaveASection(SectHandle aSection, short count)
  292. {
  293.     SectionHandle  EMSection;
  294.     OSErr          err;
  295.     Handle         tempHandle;
  296.  
  297.     HLock((Handle)aSection);
  298.  
  299.     /*save this section as its component rAliasType and rSectionType resource*/
  300.     /*also save as our own section record as a 'sect' resource*/
  301.  
  302.     EMSection  = (*aSection)->fSectHandle;
  303.     tempHandle = (Handle)EMSection;
  304.     err        = HandToHand(&tempHandle);
  305.  
  306.     HLock((Handle)EMSection);
  307.     AddResource(tempHandle, rSectionType, (*EMSection)->sectionID, "");
  308.     err = ResError();
  309.     if (err) {
  310.         ShowError("\pAddResource- rSectionType", err);
  311.         return;
  312.     }
  313.  
  314.     /*now add the alias resource*/
  315.     tempHandle = (Handle)(*EMSection)->alias;
  316.     err = HandToHand(&tempHandle);
  317.     AddResource(tempHandle, rAliasType, (*EMSection)->sectionID, "");
  318.     if (err) {
  319.         ShowError("\pAddResource- rAliasType", err);
  320.         return;
  321.     }
  322.  
  323.     /*now add our own resource- for now all the record, although we only need a few fields*/
  324.     tempHandle = (Handle)aSection;
  325.     err  = HandToHand(&tempHandle);
  326.     AddResource(tempHandle, 'SECT', count, "");
  327.     if (err) {
  328.         ShowError("\pAddResource- SECT", err);
  329.         return;
  330.     }
  331.  
  332.     HUnlock((Handle)aSection);
  333.     HUnlock((Handle)EMSection);
  334. }
  335.  
  336.  /**-----------------------------------------------------------------------
  337.         Name:         SaveSections
  338.         Purpose:        Called to go down to the section list and call SaveASection
  339.                         for each one.
  340.     -----------------------------------------------------------------------**/
  341.  
  342. #pragma segment Editions
  343.  
  344. pascal void SaveSections(DPtr aDocument)
  345. {
  346.     OSErr          err;
  347.     SectHandle     currSection;
  348.     short          count;
  349.  
  350.     if (aDocument->kind != kDocumentWindow)
  351.         return;
  352.  
  353.     /*go down the list and save each of the sections*/
  354.     /*the resource file is already open for writing*/
  355.  
  356.     count = 1;
  357.     err = ResError();
  358.     if (err) {
  359.         ShowError("\pHOpenResFile", err);
  360.         return;
  361.     }
  362.  
  363.     /*now go down the list*/
  364.     currSection = aDocument->u.reg.firstSection;
  365.     while (currSection) {
  366.         SaveASection(currSection, count);
  367.         currSection = (*currSection)->fNextSection;
  368.         count ++;
  369.     }
  370. }
  371.  
  372. /**-----------------------------------------------------------------------
  373.     Name:         AssocAllSections
  374.     Purpose:        Associate all the sections in a document with the document.
  375.                     Called on a SaveAs.
  376. -----------------------------------------------------------------------**/
  377.  
  378. #pragma segment Editions
  379.  
  380. pascal void AssocAllSections(DPtr theDoc)
  381. {
  382.     SectHandle    aSection;
  383.     SectionHandle EMSection;
  384.     OSErr         err;
  385.  
  386.     if (theDoc->kind != kDocumentWindow)
  387.         return;
  388.  
  389.     /*called by DoSaveAs.    Make sure sections are registered with this document*/
  390.     aSection = theDoc->u.reg.firstSection;
  391.     while (aSection) {
  392.         EMSection = (*aSection)->fSectHandle;
  393.         err = AssociateSection(EMSection, &theDoc->theFSSpec);
  394.         aSection  = (*aSection)->fNextSection;
  395.     }
  396. }
  397. #endif
  398.  
  399. /**-----------------------------------------------------------------------
  400.         Name:         KeyOKinSubscriber
  401.         Purpose:        Detects arrow keys.
  402.  -----------------------------------------------------------------------**/
  403. #define kChLeft    28
  404. #define kChRight    29
  405. #define kChUp        30
  406. #define kChDown    31
  407.  
  408. #pragma segment Editions
  409.  
  410. pascal Boolean KeyOKinSubscriber(char whatKey)
  411. {
  412.     return( (whatKey==kChUp) || (whatKey==kChDown) || (whatKey==kChLeft) || (whatKey==kChRight));
  413. } /*KeyOKinSubscriber*/
  414.  
  415. #ifndef RUNTIME
  416.  
  417. /**-----------------------------------------------------------------------
  418.         Name:         ShiftSection
  419.         Purpose:        Moves a section by howMany characters.
  420.  -----------------------------------------------------------------------**/
  421.  
  422. pascal void ShiftSection(SectHandle whichSection, short howMany)
  423. {
  424.     (*whichSection)->fStart += howMany;
  425.     (*whichSection)->fEnd   += howMany;
  426. }  /* ShiftSection */
  427.  
  428. /**-----------------------------------------------------------------------
  429. Name:         DoSectionRecalc
  430. Purpose:        Keeps track of the positions of the sections.
  431. -----------------------------------------------------------------------**/
  432.  
  433. #pragma segment Editions
  434.  
  435. pascal void DoSectionRecalc(DPtr theDoc, short toAdd)
  436. {
  437.     short        theStartPos;
  438.     short        theEndPos;
  439.     short        oldSectionStart;
  440.     short        oldSectionEnd;
  441.     SectHandle   aSection;
  442.     Boolean      wasChanged;
  443.     GrafPtr      oldPort;
  444.  
  445.     if (theDoc->kind != kDocumentWindow)
  446.         return;
  447.  
  448.     /*
  449.         Work thru all sections -
  450.         1) Those spanning area of modification get modified or zapped
  451.         2) Those after get shifted back or forwards.
  452.  
  453.         Sorry it is so complicated - there's a lot of possibilities
  454.     */
  455.     theStartPos = (*(theDoc->theText))->selStart;
  456.     theEndPos   = (*(theDoc->theText))->selEnd;
  457.  
  458.     aSection = theDoc->u.reg.firstSection;
  459.     while (aSection) {
  460.         wasChanged = true;
  461.  
  462.         oldSectionEnd   = (*aSection)->fEnd;
  463.         oldSectionStart = (*aSection)->fStart;
  464.  
  465.         if (theEndPos < (*aSection)->fStart)
  466.             ShiftSection(aSection, toAdd - (theEndPos-theStartPos));
  467.         else if (theStartPos == (*aSection)->fStart)
  468.             if (theEndPos == (*aSection)->fStart)
  469.                 ShiftSection(aSection, toAdd - (theEndPos-theStartPos));
  470.             else if (theEndPos >= (*aSection)->fEnd) /* section becomes pasted text */
  471.                 (*aSection)->fEnd = (*aSection)->fStart + toAdd;
  472.             else                                                                    /* insert pasted text */
  473.                 (*aSection)->fEnd = (*aSection)->fEnd + toAdd - (theEndPos-theStartPos);
  474.         else if (theStartPos< (*aSection)->fStart)
  475.             (*aSection)->fStart = theStartPos + toAdd; /* move start to end of pasted text */
  476.         else if (theStartPos <= (*aSection)->fEnd)
  477.             if (theEndPos >= (*aSection)->fEnd) /* end of section becomes pasted text */
  478.                 (*aSection)->fEnd = theStartPos + toAdd ;
  479.             else                                                                    /* insert pasted text into section */
  480.                 (*aSection)->fEnd = (*aSection)->fEnd + toAdd - (theEndPos-theStartPos);
  481.         else
  482.             wasChanged = false;
  483.  
  484.         if (wasChanged) {
  485.             (*aSection)->fCount = (*aSection)->fEnd - (*aSection)->fStart;
  486.  
  487.             if (theDoc->u.reg.showBorders) { /* Force an update of the borders - later*/
  488.                 GetPort(&oldPort);
  489.                 SetPort(theDoc->theWindow);
  490.  
  491.                 SetSelectionRgn(theDoc->theText,
  492.                                      oldSectionStart,
  493.                                      oldSectionEnd,
  494.                                      &(*aSection)->fBorderRgn);
  495.                 InvalRgn((*aSection)->fBorderRgn);
  496.  
  497.                 SetPort(oldPort);
  498.             }
  499.         }
  500.  
  501.         aSection = (*aSection)->fNextSection;
  502.     }
  503. }  /* DoSectionRecalc */
  504.  
  505. /**-----------------------------------------------------------------------
  506. Name:         ReadAnEdition
  507. Purpose:        Read the latest version of an edition from disk.
  508. -----------------------------------------------------------------------**/
  509.  
  510. #pragma segment Editions
  511.  
  512. pascal void ReadAnEdition(SectionHandle mySectHdl)
  513. {
  514.     SectHandle    aSectHandle;
  515.     EditionRefNum theRefNum;
  516.     OSErr         err;
  517.     Ptr           p;
  518.     Size          cutSize;
  519.  
  520.     p = nil;
  521.  
  522.     if (!mySectHdl) {
  523.         ShowError("\pmySectHdl is NIL", 0);
  524.         return;
  525.     }
  526.  
  527.     aSectHandle = (SectHandle)GetERefCon(mySectHdl);
  528.     if (!aSectHandle) {
  529.         ShowError("\paSectHandle is NIL", 0);
  530.         return;
  531.     }
  532.  
  533.     GetDateTime(&(*mySectHdl)->mdDate);
  534.  
  535.     /*read a subscriber in from disk.    Usually in response to a sectionread event*/
  536.  
  537.     if (err = OpenEdition(mySectHdl, &theRefNum)) {
  538.         ShowError("\pOpenEdition in ReadAnEdition", err);
  539.         return;
  540.     }
  541.  
  542.     if (err = EditionHasFormat(theRefNum, 'TEXT', &cutSize)) {
  543.         ShowError("\pEditionHasFormat in ReadAnEdition", err);
  544.         return;
  545.     }
  546.  
  547.     if (err = SetEditionFormatMark(theRefNum, 'TEXT', 0)) {
  548.         ShowError("\pSetEditionFormatMark in ReadAnEdition", err);
  549.         return;
  550.     }
  551.  
  552.     /*set up a buffer for the text we're going to read in*/
  553.     p = NewPtr(cutSize);
  554.     if (!p) {
  555.         ShowError("\pInsufficient memory to read edition", MemError());
  556.         return;
  557.     }
  558.  
  559.     if (err = ReadEdition(theRefNum, 'TEXT', p, &cutSize)) {
  560.         ShowError("\pReadEdition", err);
  561.         return;
  562.     }
  563.  
  564.     if (err = CloseEdition(theRefNum, true)) {
  565.         ShowError("\pCloseEdition", err);
  566.         return;
  567.     }
  568.  
  569.     /*
  570.         Ensure this section has a region and invalidate the old region
  571.     */
  572.  
  573.     if ((*aSectHandle)->fBorderRgn == nil)
  574.         (*aSectHandle)->fBorderRgn = NewRgn();
  575.  
  576.     SetSelectionRgn(((*aSectHandle)->fDocument)->theText,
  577.                          (*aSectHandle)->fStart,
  578.                          (*aSectHandle)->fEnd,
  579.                          &(*aSectHandle)->fBorderRgn);
  580.  
  581.     InvalRgn((*aSectHandle)->fBorderRgn);
  582.  
  583.     /*now insert the text in the right place by setting the selection range*/
  584.     /*we want this to act like paste, but without putting the contents on the clipboard*/
  585.     /*so we have to delete the current selection range and then insert our new text*/
  586.  
  587.     /*
  588.         Also fixup section info. for other moved sections
  589.     */
  590.  
  591.     TESetSelect((*aSectHandle)->fStart, (*aSectHandle)->fEnd, ((*aSectHandle)->fDocument)->theText);
  592.     DoSectionRecalc((*aSectHandle)->fDocument, cutSize);
  593.  
  594.     TEDelete(((*aSectHandle)->fDocument)->theText);
  595.     TEInsert(p, cutSize, ((*aSectHandle)->fDocument)->theText);
  596.  
  597.     /*
  598.         Now a little fix up - if the section was previously empty the
  599.         DoSectionRecalc will have put the text in before the section.
  600.         It's like that so you can type in before a subscriber in an
  601.         otherwise empty document. So now pull the start of this section
  602.         back to include the text we just added.
  603.     */
  604.  
  605.     (*aSectHandle)->fStart = (*aSectHandle)->fEnd - cutSize;
  606.  
  607.     /*
  608.         Force redraw of this region
  609.     */
  610.  
  611.     SetSelectionRgn(((*aSectHandle)->fDocument)->theText, 
  612.                          (*aSectHandle)->fStart,
  613.                          (*aSectHandle)->fEnd,
  614.                          &(*aSectHandle)->fBorderRgn);
  615.  
  616.     InvalRgn((*aSectHandle)->fBorderRgn);
  617.  
  618.     DisposPtr(p);
  619. }
  620.  
  621. /**-----------------------------------------------------------------------
  622. Name:         WriteAnEdition
  623. Purpose:        Write out the latest version of an Edition.
  624.                 Called on a Save and on selecting WriteEdition now from
  625.                 the Publisher Options dialog.
  626. -----------------------------------------------------------------------**/
  627.  
  628. #pragma segment Editions
  629.  
  630. pascal void WriteAnEdition(SectionHandle mySectHdl)
  631. {
  632.     OSErr           err;
  633.     SectHandle      aSectHandle;
  634.     EditionRefNum   theRefNum;
  635.     Handle          aHandle;
  636.     FSSpecPtr       theFSSpecPtr;
  637.  
  638.     aSectHandle = (SectHandle)GetERefCon(mySectHdl);
  639.     /*alter the modification date for the section*/
  640.     GetDateTime(&(*mySectHdl)->mdDate);
  641.     /*write out the edition.  Assume that it is a publisher for now*/
  642.     /*subscribers will be opened for writing with OpenEdition*/
  643.  
  644.     if (((*aSectHandle)->fDocument)->u.reg.everSaved == false)
  645.         theFSSpecPtr = nil;
  646.     else
  647.         theFSSpecPtr = &((*aSectHandle)->fDocument)->theFSSpec;
  648.  
  649.     if (err = OpenNewEdition(mySectHdl, MPAppSig, theFSSpecPtr, &theRefNum)) {
  650.         ShowError("\pOpenNewEdition", err);
  651.         return;
  652.     }
  653.  
  654.     if (err = SetEditionFormatMark(theRefNum, 'TEXT', 0)) {
  655.         ShowError("\pSetEditionFormatMark", err);
  656.         return;
  657.     }
  658.  
  659.     /*now get a handle to the text to be written out*/
  660.     /*use the same start and end positions for now, increasing and decreasing*/
  661.     /*the selection will be implemented later*/
  662.  
  663.     aHandle = GetHandleToText(((*aSectHandle)->fDocument)->theText,
  664.                                       (*aSectHandle)->fStart,
  665.                                       (*aSectHandle)->fEnd);
  666.     HLock(aHandle);
  667.  
  668.     /*make sure the count is up to date*/
  669.     (*aSectHandle)->fCount = (*aSectHandle)->fEnd - (*aSectHandle)->fStart;
  670.  
  671.     if (err = WriteEdition(theRefNum, 'TEXT', *aHandle, (*aSectHandle)->fCount)) {
  672.         ShowError("\pWriteEdition", err);
  673.         return;
  674.     }
  675.     HUnlock(aHandle);
  676.  
  677.     /*remember to save the section and alias records as resources later*/
  678.  
  679.     /*now close the edition*/
  680.  
  681.     if (err = CloseEdition(theRefNum, true)) {
  682.         ShowError("\pCloseEdition", err);
  683.         return;
  684.     }
  685.  
  686.     /*
  687.         Clean Up
  688.     */
  689.  
  690.     DisposHandle(aHandle);
  691. }     /*WriteAnEdition*/
  692.  
  693. /**-----------------------------------------------------------------------
  694.     Name:         WriteAllEditions
  695.     Purpose:        Go down the list and call WriteAnEdition
  696. -----------------------------------------------------------------------**/
  697.  
  698. #pragma segment  Editions
  699.  
  700. pascal void WriteAllEditions(DPtr aDocument)
  701. {
  702.     SectHandle      aSection;
  703.     SectionHandle   EMSection;
  704.  
  705.     if (aDocument->kind != kDocumentWindow)
  706.         return;
  707.         
  708.     /*called on a Save, to write out all editions*/
  709.     aSection = aDocument->u.reg.firstSection;
  710.  
  711.     while (aSection) {
  712.         EMSection = (*aSection)->fSectHandle;
  713.         if ((*EMSection)->kind == stPublisher)
  714.             WriteAnEdition(EMSection);
  715.         aSection = (*aSection)->fNextSection;
  716.     }
  717. }
  718.  
  719. /**-----------------------------------------------------------------------
  720. Name:         DeRegisterAllSections
  721. Purpose:        Called on cancel Publisher/Subscriber and on a close.
  722. -----------------------------------------------------------------------**/
  723.  
  724. #pragma segment Editions
  725.  
  726. pascal void DeRegisterAllSections(DPtr aDoc)
  727.   {
  728.         SectHandle      aSection;
  729.         SectionHandle   EMSection;
  730.         OSErr           err;
  731.  
  732.         aSection = aDoc->u.reg.firstSection;
  733.         while (aSection)
  734.             {
  735.                 EMSection = (*aSection)->fSectHandle;
  736.                 err = UnRegisterSection(EMSection);
  737.                 aSection = (*aSection)->fNextSection;
  738.             }
  739.     }
  740.  
  741. /**-----------------------------------------------------------------------
  742. Name:         GetHandleToText
  743. Purpose:        Get a handle to the current text selection.
  744.                 Used to provide a preview on Create Publisher...
  745. -----------------------------------------------------------------------**/
  746.  
  747. #pragma segment Editions
  748.  
  749. pascal Handle GetHandleToText(TEHandle aTEHandle, short theStart, short theEnd)
  750. {
  751.     OSErr     err;
  752.     Handle    myHandle;
  753.     Ptr       p;
  754.  
  755.     HLock((*aTEHandle)->hText);
  756.     p  = *((*aTEHandle)->hText);
  757.     p  += theStart;
  758.     err = PtrToHand(p, &myHandle, (theEnd - theStart));
  759.     HUnlock((*aTEHandle)->hText);
  760.     return(myHandle);
  761. } /* GetHandleToText */
  762.  
  763. /**-----------------------------------------------------------------------
  764.         Name:         FindLine
  765.         Purpose:        Find the line a character is in.
  766.                         Used to find to calculate the region to use for the Publisher/
  767.                         Subscriber borders.
  768.     -----------------------------------------------------------------------**/
  769.  
  770. #pragma segment Editions
  771.  
  772. pascal short FindLine(short thePos,TEHandle theTEHandle)
  773. {
  774.     short    index;
  775.     short    theFirstPos;
  776.     short    theNextPos;
  777.  
  778.     index = 0;
  779.  
  780.     do {
  781.         theFirstPos = (*theTEHandle)->lineStarts[index];
  782.         theNextPos  = (*theTEHandle)->lineStarts[index + 1];
  783.         index++;
  784.     } while (! (((thePos >= theFirstPos) && (thePos < theNextPos)) ||
  785.                     (index > (*theTEHandle)->nLines)));
  786.  
  787.     return(index);
  788. }
  789.  
  790. /**-----------------------------------------------------------------------
  791.         Name:         DrawSelectionRgn
  792.         Purpose:        Given a text handle and a start and end position this routine
  793.                         will draw a section border around the selected text.
  794.                         Must allow for the case when the section has no text in it-
  795.                         but we still want to show it as a published section
  796.  -----------------------------------------------------------------------**/
  797.  
  798. pascal void DrawSelectionRegion(TEHandle theTEHandle, short posStart, short posEnd)
  799. {
  800.     RgnHandle  theSelRgn;
  801.     
  802.     theSelRgn = NewRgn();
  803.     
  804.     SetSelectionRgn(theTEHandle, posStart, posEnd,&theSelRgn);
  805.     FrameRgn(theSelRgn);
  806.     
  807.     DisposeRgn(theSelRgn);
  808. } /* DrawSelectionRegion */
  809.  
  810. /**-----------------------------------------------------------------------
  811.         Name:         SetSelectionRgn
  812.         Purpose:        Given a text handle and a start and end position this routine
  813.                         will return the region which is necessary to draw a section
  814.                         border around the selected text.
  815.                         Must allow for the case when the section has no text in it-
  816.                         but we still want to show it as a published section
  817.  -----------------------------------------------------------------------**/
  818.  
  819. #pragma segment Editions
  820.  
  821. pascal void SetSelectionRgn(TEHandle theTEHandle, short posStart, short posEnd, RgnHandle *theSelRgn)
  822. {
  823.     Point           theStart;
  824.     Point           theEnd;
  825.     short           startLine;
  826.     short           endLine;
  827.     Rect            theRect;
  828.     short           theLeft;
  829.     short           theRight;
  830.     short           theBottom;
  831.     short           theTop;
  832.     short           slineHeight;
  833.     short           elineHeight;
  834.     short           fontAscent;
  835.     TextStyle       theTStyle;
  836.  
  837.     /*first of all find out if the text is on the same line*/
  838.     startLine = FindLine(posStart, theTEHandle);
  839.     endLine   = FindLine(posEnd, theTEHandle);
  840.  
  841.     theStart = TEGetPoint(posStart, theTEHandle);
  842.     theEnd   = TEGetPoint(posEnd, theTEHandle);
  843.  
  844. /*
  845. Get the line height info
  846. */
  847.     TEGetStyle(posStart, &theTStyle, &slineHeight, &fontAscent, theTEHandle);
  848.     TEGetStyle(posEnd,   &theTStyle, &elineHeight, &fontAscent, theTEHandle);
  849.  
  850.     if (startLine == endLine) {
  851.         /*use the start and end points to form the rectangle and draw this into the region*/
  852.         theStart.v -= slineHeight;
  853.         Pt2Rect(theStart, theEnd, &theRect);
  854.         InsetRect(&theRect, - 1, - 1);
  855.         RectRgn(*theSelRgn, &theRect);
  856.     } else {
  857.         theLeft  = (*theTEHandle)->destRect.left;
  858.         theRight = (*theTEHandle)->destRect.right;
  859.         theTop   = theStart.v - slineHeight;
  860.         theBottom  = theEnd.v;
  861.         OpenRgn();
  862.         MoveTo(theStart.h, theStart.v - slineHeight);
  863.         LineTo(theRight, theStart.v - slineHeight);
  864.         LineTo(theRight, theEnd.v - elineHeight);
  865.         LineTo(theEnd.h, theEnd.v - elineHeight);
  866.         LineTo(theEnd.h, theEnd.v);
  867.         LineTo(theLeft, theEnd.v);
  868.         LineTo(theLeft, theStart.v);
  869.         LineTo(theStart.h, theStart.v);
  870.         LineTo(theStart.h, theStart.v - slineHeight);
  871.         CloseRgn(*theSelRgn);
  872.     }
  873.  
  874.     InsetRgn(*theSelRgn, - 2, - 2);
  875. }
  876.  
  877. /**-----------------------------------------------------------------------
  878.         Name:         ShowSectionBorders
  879.         Purpose:        Show the borders for all the sections in a document.
  880.                         Show a Publisher border in 50% gray, a subscriber in 75% gray
  881.  -----------------------------------------------------------------------**/
  882.  
  883. #pragma segment Editions
  884.  
  885. pascal void ShowSectionBorders(DPtr aDoc)
  886. {
  887.     SectHandle aSection;
  888.  
  889.     if (aDoc->kind != kDocumentWindow)
  890.         return;
  891.         
  892.     PenNormal();
  893.     PenSize(3, 3);
  894.     PenPat(&qd.gray);
  895.     aSection = aDoc->u.reg.firstSection;
  896.     while (aSection) {
  897.         if ((*aSection)->fBorderRgn) {
  898.             SetSelectionRgn(((*aSection)->fDocument)->theText,
  899.                                  (*aSection)->fStart,
  900.                                  (*aSection)->fEnd,
  901.                                  &(*aSection)->fBorderRgn);
  902.  
  903.             if ((*(*aSection)->fSectHandle)->kind == stPublisher)
  904.                 PenPat(&qd.gray);
  905.             else
  906.                 PenPat(&qd.dkGray);
  907.  
  908.             FrameRgn((*aSection)->fBorderRgn);
  909.             PenNormal();
  910.         }
  911.         aSection = (*aSection)->fNextSection;
  912.     }
  913.     PenNormal();
  914. }
  915.  
  916. /**-----------------------------------------------------------------------
  917.         Name:         RecalcBorders
  918.         Purpose:        Recalculate all the borders for the sections in a document.
  919.  -----------------------------------------------------------------------**/
  920.  
  921. #pragma segment Editions
  922.  
  923. pascal void RecalcBorders(DPtr aDoc, Boolean invalidate)
  924. {
  925.     SectHandle  aSection;
  926.  
  927.     if (aDoc->kind != kDocumentWindow)
  928.         return;
  929.         
  930.     /*go down the section list and recalculate all the borders*/
  931.     aSection = aDoc->u.reg.firstSection;
  932.     while (aSection) {
  933.         if ((*aSection)->fBorderRgn) {
  934.             if (invalidate)
  935.                 InvalRgn((*aSection)->fBorderRgn);
  936.  
  937.             SetSelectionRgn(((*aSection)->fDocument)->theText,
  938.                                  (*aSection)->fStart,
  939.                                  (*aSection)->fEnd,
  940.                                  &(*aSection)->fBorderRgn);
  941.  
  942.             if (invalidate)
  943.                 InvalRgn((*aSection)->fBorderRgn);
  944.         }
  945.         aSection = (*aSection)->fNextSection;
  946.     }
  947. }
  948.  
  949. /**-----------------------------------------------------------------------
  950.         Name:         GetSection
  951.         Purpose:        Given a start and end of a selection- return the section
  952.                         handle if it is in a Publisher or Subscriber.
  953.  -----------------------------------------------------------------------**/
  954.  
  955. #pragma segment Editions
  956.  
  957. pascal SectHandle GetSection(short theStartPos, short theEndPos, DPtr aDoc)
  958. {
  959.     SectHandle   foundSection;
  960.     SectHandle   aSection;
  961.  
  962.     /*returns the section handle for the section between theStartPos and theEndPos*/
  963.  
  964.     if (aDoc->kind != kDocumentWindow)
  965.         return nil;
  966.         
  967.     foundSection = nil;
  968.  
  969.     aSection = aDoc->u.reg.firstSection;
  970.     while (aSection) {
  971.         if ((theStartPos >= (*aSection)->fStart) && (theEndPos <= (*aSection)->fEnd))
  972.             foundSection = aSection;
  973.         aSection = (*aSection)->fNextSection;
  974.     }
  975.  
  976.     return foundSection;
  977. }
  978.  
  979. /**-----------------------------------------------------------------------
  980.         Name:         DoTEPasteSectionRecalc
  981.         Purpose:        Keeps track of the positions of the sections call before a
  982.                     TEPaste or TEStylPaste.
  983.  -----------------------------------------------------------------------**/
  984.  
  985. pascal void DoTEPasteSectionRecalc(DPtr theDoc)
  986. {
  987.     short toAdd;
  988.  
  989.     if (theDoc->kind != kDocumentWindow)
  990.         return;
  991.         
  992.     toAdd = TEGetScrapLen();
  993.     DoSectionRecalc(theDoc, toAdd);
  994. }  /* DoTEPasteSectionRecalc */
  995.  
  996. /**-----------------------------------------------------------------------
  997.         Name:         DoTEDeleteSectionRecalc
  998.         Purpose:        Keeps track of the positions of the sections call before a
  999.                     TEDelete.
  1000.  -----------------------------------------------------------------------**/
  1001.  
  1002. pascal void DoTEDeleteSectionRecalc(DPtr theDoc)
  1003. {
  1004.     if (theDoc->kind != kDocumentWindow)
  1005.         return;
  1006.         
  1007.     DoSectionRecalc(theDoc, 0);
  1008. }  /* DoTEDeleteSectionRecalc */
  1009.  
  1010. /**-----------------------------------------------------------------------
  1011.         Name:         DoTECutSectionRecalc
  1012.         Purpose:        Keeps track of the positions of the sections call before a
  1013.                     TECut.
  1014.  -----------------------------------------------------------------------**/
  1015.  
  1016. pascal void DoTECutSectionRecalc(DPtr theDoc)
  1017. {
  1018.     if (theDoc->kind != kDocumentWindow)
  1019.         return;
  1020.         
  1021.     DoSectionRecalc(theDoc, 0);
  1022. }  /* DoTEDeleteSectionRecalc */
  1023.  
  1024. /**-----------------------------------------------------------------------
  1025.         Name:         DoTEKeySectionRecalc
  1026.         Purpose:        Keeps track of the positions of the sections call before a
  1027.                     TECut.
  1028.  -----------------------------------------------------------------------**/
  1029.  
  1030. pascal void DoTEKeySectionRecalc(DPtr theDoc,char theChar)
  1031. {
  1032.     short     toAdd;
  1033.     short     oldStart;
  1034.  
  1035.     if (theDoc->kind != kDocumentWindow)
  1036.         return;
  1037.         
  1038.     if (!KeyOKinSubscriber(theChar)) /* is it a cursor motion key? - yes = ignore */ {
  1039.         if (theChar==8)
  1040.             if ((*(theDoc->theText))->selStart<(*(theDoc->theText))->selEnd)
  1041.                 toAdd = 0;
  1042.             else {
  1043.                 toAdd = -1;
  1044.                 oldStart = (*(theDoc->theText))->selStart;
  1045.  
  1046.                 (*(theDoc->theText))->selStart = GreaterOf(oldStart-1,0);
  1047.                 DoSectionRecalc(theDoc, 0);
  1048.                 (*(theDoc->theText))->selStart = oldStart;
  1049.             }
  1050.         else
  1051.             toAdd = 1;
  1052.  
  1053.         if (toAdd!=-1)
  1054.             DoSectionRecalc(theDoc, toAdd);
  1055.     }
  1056. }  /* DoTEKeySectionRecalc */
  1057.  
  1058. /**-----------------------------------------------------------------------
  1059.         Name:         GetEditionContainer
  1060.         Purpose:        Gets the Edition Container to put the edition into.
  1061.                         The main user interface stuff.
  1062.                         Puts up the new publisher dialog.
  1063.                         Should check kAEInteractWithUser etc.
  1064.  -----------------------------------------------------------------------**/
  1065.  
  1066. #pragma segment Main
  1067.  
  1068. pascal OSErr GetEditionContainer(DPtr theDoc, FSSpec *theFSSpec)
  1069. {
  1070.     OSErr             err;
  1071.     NewPublisherReply myReply;
  1072.     short             theStart;
  1073.     short             theEnd;
  1074.     Handle            myHandle;
  1075.     TEHandle          myText;
  1076.  
  1077.     if (theDoc->kind != kDocumentWindow)
  1078.         return noErr;
  1079.         
  1080.     err = noErr;
  1081.  
  1082.     /*get default editionContainer to use, using last volume and folder*/
  1083.  
  1084.     myReply.container.thePart = kPartsNotUsed;
  1085.  
  1086.     err = GetLastEditionContainerUsed(&myReply.container);
  1087.  
  1088.     if (err==fnfErr)
  1089.         err = noErr;
  1090.  
  1091.     myText = theDoc->theText;
  1092.  
  1093.     theStart = (*myText)->selStart;
  1094.     theEnd   = (*myText)->selEnd;
  1095.  
  1096.     if (err==noErr) {
  1097.         /*
  1098.             Create a handle containing the text to be published for previewing -
  1099.             need to ask the user where to put the data
  1100.         */
  1101.         myHandle = GetHandleToText(myText, theStart, theEnd);
  1102.  
  1103.         myReply.usePart       = false;
  1104.         myReply.preview       = myHandle;
  1105.         myReply.previewFormat = 'TEXT';
  1106.         myReply.container.theFile.name[0] = 0; /* Want a proper prompted name here */
  1107.         HLock(myHandle);
  1108.  
  1109.         /* Should take suggested name and avoid dialog if no user interaction */
  1110.  
  1111.         err = AEInteractWithUser(kAEDefaultTimeout, nil, nil);
  1112.  
  1113.         err = NewPublisherDialog(&myReply);
  1114.         HUnlock(myHandle);
  1115.         DisposHandle(myHandle);
  1116.     }
  1117.  
  1118.     /*IF user cancelled, THEN exit from this routine*/
  1119.  
  1120.     if (err==noErr)
  1121.         if (myReply.canceled)
  1122.             err = userCanceledErr; /* User cancelled marker - replace later */
  1123.  
  1124.     if (err==noErr)
  1125.         if (myReply.replacing)
  1126.             err = FSpDelete(&myReply.container.theFile);
  1127.  
  1128.     if (err == noErr)
  1129.         *theFSSpec = myReply.container.theFile;
  1130.  
  1131.     return(err);
  1132. } /*GetEditionContainer*/
  1133.  
  1134.  
  1135. /**-----------------------------------------------------------------------
  1136.         Name:             PublishText
  1137.         Purpose:        Publishes the current selection of theDoc.
  1138.                                 The main user interface stuff.
  1139.                                 Puts up the new publisher dialog - if theFSSpec=NIL
  1140.                                 Writes the new edition out to disk.
  1141.  -----------------------------------------------------------------------**/
  1142.  
  1143. #pragma segment Main
  1144.  
  1145. pascal OSErr PublishText(DPtr theDoc, FSSpecPtr theFSSpec)
  1146. {
  1147.     NewPublisherReply myReply;
  1148.     SectionHandle        mySectHdl;
  1149.     OSErr                 err;
  1150.     long               mysectionID;
  1151.     FSSpecPtr             pubFSSpec;
  1152.     short                 theStart;
  1153.     short                 theEnd;
  1154.     RgnHandle             theRgnHandle;
  1155.  
  1156.     if (theDoc->kind != kDocumentWindow)
  1157.         return noErr;
  1158.         
  1159.     mysectionID            = theDoc->u.reg.lastID + 1;
  1160.     theDoc->u.reg.lastID = mysectionID;
  1161.  
  1162.     /*get default editionContainer to use, using last volume and folder*/
  1163.  
  1164.     myReply.container.thePart = kPartsNotUsed;
  1165.  
  1166.     err = GetLastEditionContainerUsed(&myReply.container);
  1167.  
  1168.     if (err==fnfErr)
  1169.         err = noErr;
  1170.  
  1171.     theStart = (*theDoc->theText)->selStart;
  1172.     theEnd   = (*theDoc->theText)->selEnd;
  1173.  
  1174.     /*don't want to publish an empty section*/
  1175.  
  1176.     if (theEnd - theStart == 0)
  1177.         err = userCanceledErr;
  1178.  
  1179.     myReply.container.theFile = *theFSSpec;
  1180.  
  1181.     /*now publish this section*/
  1182.  
  1183.     if (err == noErr)
  1184.         err = CreateEditionContainerFile(&myReply.container.theFile, MPAppSig, 0);
  1185.  
  1186.     /*check IF the file has been saved, IF not set pubCFS to NIL*/
  1187.  
  1188.     if (theDoc->u.reg.everSaved == false)
  1189.         pubFSSpec = nil;
  1190.     else
  1191.         pubFSSpec = &theDoc->theFSSpec;
  1192.  
  1193.     /*get the region to encompass the selection*/
  1194.  
  1195.     theRgnHandle = NewRgn();
  1196.     SetSelectionRgn(theDoc->theText,
  1197.                          (*theDoc->theText)->selStart,
  1198.                                     (*theDoc->theText)->selEnd,
  1199.                                     &theRgnHandle);
  1200.  
  1201.     InvalRgn(theRgnHandle);
  1202.  
  1203.     /*create a publisher section*/
  1204.     if (err==noErr) {
  1205.         err = NewSection(&myReply.container,
  1206.                               pubFSSpec,
  1207.                               stPublisher,
  1208.                               mysectionID,
  1209.                               pumOnSave,
  1210.                               &mySectHdl);
  1211.  
  1212.         /*now add this section to our document list*/
  1213.  
  1214.         if (err == noErr)
  1215.             CreateSection(mySectHdl, mysectionID, theStart, theEnd, theDoc, theRgnHandle);
  1216.     }
  1217.  
  1218.     /*now write out the edition to file*/
  1219.  
  1220.     if (err==noErr)
  1221.         WriteAnEdition(mySectHdl);
  1222.  
  1223.     return(err);
  1224. } /*PublishText*/
  1225.  
  1226. /**-----------------------------------------------------------------------
  1227.         Name:         DoSubscribe
  1228.         Purpose:        Subscribe to a published section. Puts up the subscriber
  1229.                         dialog, creates and adds the new section.
  1230.  -----------------------------------------------------------------------**/
  1231.  
  1232. #pragma segment  Main
  1233.  
  1234. pascal void DoSubscribe(DPtr theDoc)
  1235. {
  1236.     NewSubscriberReply myReply;
  1237.     SectionHandle      mySectHdl;
  1238.     long               mysectionID;
  1239.     FSSpecPtr          subFSSpec; /*the fsspec for the subscriber file*/
  1240.     OSErr              err;
  1241.     short              theStart;
  1242.     short              theEnd;
  1243.  
  1244.     if (theDoc->kind != kDocumentWindow)
  1245.         return;
  1246.         
  1247.     mysectionID = theDoc->u.reg.lastID + 1;
  1248.     theDoc->u.reg.lastID = mysectionID;
  1249.     err = noErr;
  1250.  
  1251.     /*get default editionContainer to use, using last volume and folder*/
  1252.     /*  myreply.container.thePart := kPartNumberUnknown;*/
  1253.     myReply.formatsMask = kTEXTformatMask;
  1254.  
  1255.     err = GetLastEditionContainerUsed(&myReply.container);
  1256.     if (err && (err !=fnfErr)) {
  1257.         ShowError("\pGetLastEditionContainerUsed", err);
  1258.         return;
  1259.     }
  1260.  
  1261.     /*put up the subscriber dialog*/
  1262.     err = NewSubscriberDialog(&myReply);
  1263.     if (err && (err !=fnfErr)) {
  1264.         ShowError("\pNewSubscriberDialog", err);
  1265.         return;
  1266.     }
  1267.  
  1268.     if (myReply.canceled)
  1269.         return;
  1270.  
  1271.     /*check IF the file has been saved, IF not set pubCFS to NIL*/
  1272.     if (theDoc->u.reg.everSaved == false)
  1273.         subFSSpec = nil;
  1274.     else
  1275.         subFSSpec = &theDoc->theFSSpec;
  1276.  
  1277.     /*create a publisher section*/
  1278.     err = NewSection(&myReply.container,
  1279.                           subFSSpec,
  1280.                           stSubscriber,
  1281.                           mysectionID,
  1282.                           sumAutomatic,
  1283.                           &mySectHdl);
  1284.  
  1285.     if (err) {
  1286.         ShowError("\pNewSection", err);
  1287.         return;
  1288.     }
  1289.  
  1290.     theStart = (*theDoc->theText)->selStart;
  1291.     theEnd   = (*theDoc->theText)->selEnd;
  1292.  
  1293.     /*now add this section to our document list*/
  1294.  
  1295.     CreateSection(mySectHdl, mysectionID, theStart, theEnd, theDoc, nil);
  1296.  
  1297.     /*read the subscriber in from disk*/
  1298.  
  1299.     ReadAnEdition(mySectHdl);
  1300.  
  1301. }  /*DoSubscribe*/
  1302.  
  1303. /**-----------------------------------------------------------------------
  1304.         Name:         DoSectionOptions
  1305.         Purpose:        Put up the section option dialogs for a publisher
  1306.                         or subscriber.    Handle all the various options.
  1307.                         Note that 'Find Publisher' doesn't work yet.
  1308.  -----------------------------------------------------------------------**/
  1309.  
  1310. #pragma segment  Main
  1311.  
  1312. pascal void DoSectionOptions(DPtr theDoc)
  1313. {
  1314.     OSErr               err;
  1315.     SectionOptionsReply reply;
  1316.     EditionInfoRecord   theInfo;
  1317.     SectHandle          currSection;
  1318.  
  1319.     if (theDoc->kind != kDocumentWindow)
  1320.         return;
  1321.         
  1322.     currSection = GetSection((*theDoc->theText)->selStart,
  1323.                                                      (*theDoc->theText)->selEnd,
  1324.                                                      theDoc);
  1325.  
  1326.     reply.sectionH = (*currSection)->fSectHandle;
  1327.     err = SectionOptionsDialog(&reply);
  1328.     if (!reply.canceled) {
  1329.         /*find out IF there is any action needed*/
  1330.         if (reply.action == 'read')
  1331.         /*read the latest version of a subscriber*/
  1332.             ReadAnEdition((*currSection)->fSectHandle);
  1333.         else if (reply.action == 'writ')
  1334.         /*write out the latest version of a publisher to disk*/
  1335.             WriteAnEdition((*currSection)->fSectHandle);
  1336.         else if (reply.action == 'goto') /*goto a published section*/ {
  1337.             err = GetEditionInfo((*currSection)->fSectHandle, &theInfo);
  1338.  
  1339.             if (err)
  1340.                 ShowError("\pGetEditionInfo", err);
  1341.  
  1342.             err = GoToPublisherSection(&theInfo.container);
  1343.  
  1344.             if (err)
  1345.                 ShowError("\pGotoPublisherSection", err);
  1346.         } else if (reply.action == 'cncl') /*cancel a publisher or subscriber*/ {
  1347.             /*unRegister the section and delete from our own list*/
  1348.             /*should have a free PROCEDURE which frees the structures*/
  1349.             /*associated with a section*/
  1350.             err = UnRegisterSection((*currSection)->fSectHandle);
  1351.             DeleteASection(currSection, theDoc);
  1352.  
  1353.             /*IF this is the ONLY publisher writing data to this edition*/
  1354.             /*we should delete the container file as well*/
  1355.         }
  1356.     }
  1357. }
  1358.  
  1359. #endif